/**
 * @namespace
 */
$.aws.walker = {
	/**
	 * Subscribes to various events
	 */
	init: function() {
		$.aws.observer.subscribe('exec', 'walker', $.aws.walker.exec);
		$.aws.observer.subscribe('keypress', 'keypress-walker', $.aws.walker.keypress);
		$.aws.observer.subscribe('setRootWaypoint', 'setRootWaypoint-walker', $.aws.walker.setRootWaypoint);
		$.aws.observer.subscribe('goToNextWaypoint', 'goToNextWaypoint-walker', $.aws.walker.goToNextWaypoint);
		$.aws.observer.subscribe('goToPreviousWaypoint', 'goToPreviousWaypoint-walker', $.aws.walker.goToPreviousWaypoint);
		$.aws.observer.subscribe('updateWaypointValue', 'updateWaypointValue-walker', $.aws.walker.updateWaypointValue);
		$.aws.observer.subscribe('unsetRootWaypoint', 'unsetRootWaypoint-walker', $.aws.walker.unsetRootWaypoint);
		$.aws.observer.subscribe('reset', 'reset-walker', $.aws.walker.reset);
		$.aws.walker.initiated = true;
	},
	/**
	 * Checks if waypoint has code awailable to execute and executes it
	 */
	exec: function() {
		$.aws.waypoint.onEnter && $.aws.waypoint.onEnter.isAvailable() && $.aws.waypoint.onEnter.exec();
	},
	/**
	 * Sets first (root) waypoint
	 * @param {String} key Key of waypoint
	 */
	setRootWaypoint: function(key) {
		if ($.aws.pathes[key]) {
			$.aws.waypoint = $.aws.pathes[key];
			$.aws.waypoint.previous = $.aws.waypoint[key];
			$.aws.observer.notify('waypointChanged');
			$.aws.observer.notify('goneToNextWaypoint');
			$.aws.observer.notify('rootWaypointSet');
		}
	},
	/**
	 * Moves to next waypoint
	 * @param {String} key Key of next waypoint. Can be omitted, if next waypoint is of "value" type.
	 */
	goToNextWaypoint: function(key) {
		if ($.aws.waypoint.next) {
			var prev = $.aws.waypoint;
			if (typeof $.aws.waypoint.next.value != 'undefined') {
				$.aws.waypoint = $.aws.waypoint.next;
			} else if ($.aws.waypoint.next[key]) {
				$.aws.waypoint = $.aws.waypoint.next[key];
			} else {
				return;
			}
			$.aws.waypoint.previous = prev;
			$.aws.observer.notify('goneToNextWaypoint');
		}
	},
	/**
	 * Moves to previous waypoint. Unsets root waypoint, if there are no previous.
	 */
	goToPreviousWaypoint: function() {
		if ($.aws.waypoint.previous) {
			$.aws.waypoint = $.aws.waypoint.previous;
			$.aws.observer.notify('goneToPreviousWaypoint');
		} else {
			$.aws.observer.notify('unsetRootWaypoint');
		}
	},
	/**
	 * Changes value of current waypoint (which should be of "value" type).
	 * @param {String} value New value of waypoint
	 */
	updateWaypointValue: function(value) {
		$.aws.waypoint.value = value;
		$.aws.observer.notify('waypointValueChanged');
	},
	/**
	 * Unsets root waypoint, so there are no waypoints choosed.
	 */
	unsetRootWaypoint: function() {
		delete $.aws.waypoint;
		$.aws.observer.notify('rootWaypointUnset');
	},
	/**
	 * Similar to unsetRootWaypoint, but doesn't send any notifications. Designed to respond to global reset event.
	 */
	reset: function() {
		$.aws.waypoint.value = '';
		delete $.aws.waypoint;
	},
	/**
	 * Decides if any manipulations should be done with waypont when keyboard keys got pressed
	 * @param {String} code Code of pressed keyboard key
	 * @param {Object} e Event
	 */
	keypress: function(code, e) {
		if (code == 13 && $.aws.waypoint) {
			$.aws.observer.notify('exec');
		} else if (code == 8 && $.aws.waypoint) {
			if ($.aws.waypoint.value) {
				$.aws.observer.notify('updateWaypointValue', [$.aws.waypoint.value.substr(0, $.aws.waypoint.value.length - 1)]);
			} 
			if (!$.aws.waypoint.value) {
				$.aws.observer.notify('goToPreviousWaypoint');
			}
		} else {
			var key = String.fromCharCode(code).toLowerCase();
			if (key) {
				if ($.aws.waypoint) {
					if (!$.aws.waypoint.value) {
						$.aws.observer.notify('goToNextWaypoint', [key]);
					}
					if (typeof $.aws.waypoint.value != 'undefined') {
						$.aws.observer.notify('updateWaypointValue', [$.aws.waypoint.value + key]);
					}
				} else {
					$.aws.observer.notify('setRootWaypoint', [key]);
				}
			}
		}
	}
};

/** Module should be initialized on global init event */
$.aws.observer.subscribe('init', 'init-walker', $.aws.walker.init);
